﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AuthApi.Contracts;
using System.DirectoryServices;
using Web.Framework;
using ApiAuth.Data;
using System.Configuration;

namespace ApiAuth.Services
{
    public class AuthApiService : IAuthApi
    {
        public bool ValidateUser(int applicationId, int companyId, String username, String password)
        {
            bool isAuthenticated = false;

            using (ApiAuthEntities ctx = new ApiAuthEntities())
            {
                var dbUser = ctx.DbAppUsers.Where(u => u.UserName == username).SingleOrDefault();

                if (dbUser != null)
                {
                    DbCompanyApplicationUser user;
                    if (companyId == 0)
                    {
                        user = dbUser.CompanyApplicationUsers.Where(ca => ca.ApplicationId == applicationId && !ca.CompanyId.HasValue).SingleOrDefault();
                    }
                    else
                    {
                        user = dbUser.CompanyApplicationUsers.Where(ca => ca.ApplicationId == applicationId && ca.CompanyId == companyId).SingleOrDefault();
                    }                    

                    if (user != null)
                    {
                        if (!user.Blocked && !dbUser.Blocked)
                        {
                            DbApplication application = ctx.DbApplications.Where(a => a.Id == applicationId).Single();
                            DbCompany company = ctx.DbCompanies.Where(c => c.Id == companyId).SingleOrDefault();

                            string adPathStr;
                            string domainStr;

                            if (application.RequiereLoginSinEmpresa)
                            {
                                adPathStr = application.AdPath;
                                domainStr = application.Domain;
                            }
                            else
                            {
                                adPathStr = company.AdPath;
                                domainStr = company.Domain;
                            }

                            isAuthenticated = IsAdAuthenticated(adPathStr, domainStr, username, password);
                            // LDAP://lexisnexis.com.ar/DC=lexisnexis,DC=com,DC=ar 
                            // LDAP://vesuvio.argentina/DC=vesuvio,DC=argentina


                            if (!isAuthenticated)
                            {
                                isAuthenticated = IsAppAuthenticated(dbUser, password);
                            }
                        }
                        else
                        {
                            isAuthenticated = false;
                        }
                    }
                }
            }

            return isAuthenticated;
        }

        /// <summary>
        /// Controla que autentique por aplicación
        /// </summary>
        /// <param name="user"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        private bool IsAppAuthenticated(DbAppUser user, string password)
        {
            string hashedPassword = ApiCommon.HashPassword(password, user.UserName);
            return hashedPassword == user.Password;
        }

        public bool ResetPassword(string username)
        {
            bool success = false;
            using (ApiAuthEntities ctx = new ApiAuthEntities())
            {
                var dbUser = ctx.DbAppUsers.Where(u => u.UserName == username).SingleOrDefault();

                if (dbUser != null)
                {
                    //var user = dbUser.CompanyApplicationUsers.Where(ca => ca.ApplicationId == applicationId && ca.CompanyId == companyId).SingleOrDefault();                  

                    if (dbUser != null)
                    {
                        // Asigno el nuevo passowrd
                        dbUser.Password = string.Empty;
                        ctx.SaveChanges();
                        success = true;
                    }
                }
            }

            return success;
        }

        public bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            bool success = false;
            using (ApiAuthEntities ctx = new ApiAuthEntities())
            {
                var dbUser = ctx.DbAppUsers.Where(u => u.UserName == username).SingleOrDefault();

                if (dbUser != null)
                {
                    //var user = dbUser.CompanyApplicationUsers.Where(ca => ca.ApplicationId == applicationId && ca.CompanyId == companyId).SingleOrDefault();                  

                    if (dbUser != null)
                    {
                        if (!String.IsNullOrEmpty(dbUser.Password))
                        {
                            string hashUserOld = dbUser.Password;
                            string hashUserInputOld = ApiCommon.HashPassword(oldPassword, dbUser.UserName);
                            if (hashUserOld == hashUserInputOld)
                            {
                                dbUser.Password = ApiCommon.HashPassword(newPassword, dbUser.UserName);
                                ctx.SaveChanges();
                                success = true;
                            }
                        }
                        else
                        {
                            // Asigno el nuevo passowrd
                            dbUser.Password = ApiCommon.HashPassword(newPassword, dbUser.UserName);
                            ctx.SaveChanges();
                            success = true;
                        }
                    }
                }
            }

            return success;
        }

        public List<AdUser> GetUsers(int applicationId, int companyId, string userName)
        {
            using (ApiAuthEntities ctx = new ApiAuthEntities())
            {
                IQueryable<DbCompanyApplicationUser> query = ctx.DbCompanyApplicationUsers.Where(u => u.ApplicationId == applicationId);

                if (companyId == 0)
                {
                    query = query.Where(u => !u.CompanyId.HasValue);
                }
                else
                {
                    query = query.Where(u => u.CompanyId == companyId);
                }

                if (!String.IsNullOrEmpty(userName))
                {
                    query = query.Where(u => u.AppUser.UserName == userName);
                }

                var users = query.OrderBy(u => u.AppUser.UserName).ToList();

                List<AdUser> adUserList = new List<AdUser>();
                foreach (var dbUser in users)
                {
                    AdUser adUser = new AdUser();

                    adUser.Id = dbUser.Id;
                    adUser.UserName = dbUser.AppUser.UserName;
                    adUser.GivenName = dbUser.AppUser.GivenName;
                    adUser.ApplicationId = dbUser.ApplicationId;
                    adUser.CompanyId = dbUser.CompanyId ?? 0;
                    adUser.Blocked = dbUser.Blocked;
                    adUser.BlockedDate = dbUser.BlockedDate;
                    adUser.UnBlockedDate = dbUser.UnblockedDate;
                    adUser.HasPassword = !String.IsNullOrEmpty(dbUser.AppUser.Password);

                    adUserList.Add(adUser);
                }

                return adUserList;
            }
        }

        public List<string> GetOperationsForUser(int applicationId, int companyId, String username)
        {
            List<string> operations = new List<string>();
            using (ApiAuthEntities ctx = new ApiAuthEntities())
            {
                var dbUser = ctx.DbAppUsers.Where(u => u.UserName == username).SingleOrDefault();

                if (dbUser != null)
                {
                    DbCompanyApplicationUser user;
                    if (companyId == 0)
                    {
                        user = dbUser.CompanyApplicationUsers.Where(ca => ca.ApplicationId == applicationId && !ca.CompanyId.HasValue).SingleOrDefault();
                    }
                    else
                    {
                        user = dbUser.CompanyApplicationUsers.Where(ca => ca.ApplicationId == applicationId && ca.CompanyId == companyId).SingleOrDefault();
                    }

                    if (user != null)
                    {
                        if (!user.Blocked)
                        {
                            int? companyNullableId = companyId == 0 ? (int?)null : companyId;
                            operations.AddRange(ctx.GetOperationsForUser(applicationId, companyNullableId, username).ToList());
                        }
                    }
                }

                return operations;
            }
        }

        public List<Company> GetCompanies(int applicationId)
        {
            List<Company> companies = new List<Company>();
            using (ApiAuthEntities ctx = new ApiAuthEntities())
            {
                companies.AddRange((from c in ctx.DbCompanies
                                    where (from compApp in c.CompanyApplications where compApp.ApplicationId == applicationId select 1).Count() > 0
                                    select new Company()
                            {
                                Id = c.Id,
                                AdPath = c.AdPath,
                                Domain = c.Domain,
                                Name = c.Name
                            }).ToList());
            }

            return companies;
        }

        public static bool IsAdAuthenticated(string adPath, string domain, string username, string pwd)
        {
            string domainAndUsername = domain + @"\" + username;
            DirectoryEntry entry = new DirectoryEntry(adPath, domainAndUsername, pwd);

            bool isAutenticated = false;

            try
            {
                Object obj = entry.NativeObject;
                DirectorySearcher search = new DirectorySearcher(entry);
                search.Filter = "(SAMAccountName=" + username + ")";
                search.PropertiesToLoad.Add("cn");
                SearchResult result = search.FindOne();
                isAutenticated = null != result;
            }
            catch (Exception ex)
            {
                Exception ex1 = new Exception("Error Autenticando al usuario: " + ex.Message, ex);
            }

            return isAutenticated;
        }
    }
}
